iT邦幫忙

0

Kotlin - 當CoroutineScope中發生Exception的各種狀況

  • 分享至 

  • xImage
  •  

先談談於coroutine中發生exception的時候會有什麼事情發生,先來看看一般的狀況

import kotlinx.coroutines.*

suspend fun getUsers(): List<String> {
    delay(100L)
    println("getUsers()")
    return listOf("Alice","John")
}

suspend fun getMoreUsers(): List<String> {
    delay(100L)
    throw java.io.IOException("Hello")
    return listOf("Tom","Jeff")
}

fun main() = runBlocking {    
    try {        
        val usersDeferred = async { getUsers() }
        val moreUsersDeferred = async { getMoreUsers() }
        val users = usersDeferred.await()
        val moreUsers = moreUsersDeferred.await()
    } catch (exception: java.io.IOException) {
       println("execption...")
    }
}

可以看到結果,即使進行了try catch,還是會導致appCrash,也就是在coroutine 中的exception其實會引發CancellationException

getUsers()
execption...
Exception in thread "main" java.io.IOException: Hello
 at FileKt.getMoreUsers (File.kt:11) 
 at FileKt$getMoreUsers$1.invokeSuspend (File.kt:-1) 
 at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33) 

透過corotuineScope builder 來執行

接著我們透過在coroutine的extension有提供一個builder corotuineScope

特色

  1. 可以抓捕內部coroutine的exception
  2. 會馬上取消剩下的coroutine

他的source code

public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return suspendCoroutineUninterceptedOrReturn { uCont ->
        val coroutine = ScopeCoroutine(uCont.context, uCont)
        coroutine.startUndispatchedOrReturn(coroutine, block)
    }
}

範例:

import kotlinx.coroutines.*

suspend fun getUsers(): List<String> {
    delay(100L)
    println("getUsers()")
    return listOf("Alice","John")
}

suspend fun getMoreUsers(): List<String> {
    delay(100L)
    throw java.io.IOException("Hello")
    return listOf("Tom","Jeff")
}

suspend fun runHello() {
    delay(300L)
    println("runHello still alive...")
}

fun main() = runBlocking {    
    try {        
        coroutineScope {
            val usersDeferred = async { getUsers() }
            val moreUsersDeferred = async { getMoreUsers() }
            val users = usersDeferred.await()
            runHello()
        }
    } catch (exception: java.io.IOException) {
       println("execption...")
    }
}

也就是加上coroutineScope後,他會有抓捕從coroutine拋出exception的能力,也會得到這樣的log,如同我們平常執行regular function call的流程

getUsers()
execption...

這樣應該就也比較符合我們期待,也不會導致app Crash


那supervisorScope 又是什麼?

特色

  1. 會捕抓exception會不理,也不會crash
  2. 發生exceptoin的coroutine不會被處理,但剩下的coroutine會繼續執行

看一下source code

public suspend fun <R> supervisorScope(block: suspend CoroutineScope.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return suspendCoroutineUninterceptedOrReturn { uCont ->
        val coroutine = SupervisorCoroutine(uCont.context, uCont)
        coroutine.startUndispatchedOrReturn(coroutine, block)
    }
}

如同下方的runHello即使上方遇到crash,他還是會繼續執行

import kotlinx.coroutines.*

suspend fun getUsers(): List<String> {
    delay(100L)
    println("getUsers()")
    return listOf("Alice","John")
}

suspend fun getMoreUsers(): List<String> {
    delay(100L)
    throw java.io.IOException("Hello")
    return listOf("Tom","Jeff")
}

suspend fun runHello() {
    delay(100L)
    println("runHello still alive...")
}

fun main() = runBlocking {    
    try {        
        supervisorScope {
            val usersDeferred = async { getUsers() }
            val moreUsersDeferred = async { getMoreUsers() }
            val users = usersDeferred.await()
            runHello()            
        }
    } catch (exception: java.io.IOException) {
       println("execption...")
    }
}

因此這兩種有兩個不同的使用場景跟應用,所以很簡單的端看你自己的應用場景是怎麼使用,總結一下

不加scope - 即使有try catch,也不會被捕抓,app 會crash
corotuineScope - 會抓exception,會產生try-catch,同時停止其他corotuine
supervisorScope - 會抓exception,不會產生try-catch,但不會停止其他的corotuine

參考

https://waynestalk.com/kotlin-coroutine-tutorial/

https://amitshekhar.me/blog/kotlin-coroutines

https://kotlinlang.org/docs/exception-handling.html#exception-propagation


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言